package servidorchat;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Date;
import java.io.*;
import java.net.*;

public class ThreadServidor extends Thread{
	
	private String nombreCliente;
        private String nombreSala;

	
	private static String historial = "c:/historial.txt";
	
	private static List clientesActivos = new ArrayList();
        private static List salas = new ArrayList();
	
	private Socket socket;
	
	//flujos de E/S
	private BufferedReader entrada;
	private PrintWriter salida;
	
	public ThreadServidor(Socket socket) throws IOException {
		this.socket = socket;
		
		entrada = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		
		salida = new PrintWriter(socket.getOutputStream(),true);
		
		escribirHistorial("Conexion desde la direccion");
		start();
	}
	
	public void run(){
		String textoUsuario = "";
		try{
			salida.println("server>Bienvenido a este chat");
			salida.println("server>Introduzca su nombre,por favor :");
			
			nombreCliente = entrada.readLine().trim();
			if(nombreCliente.equals("") || nombreCliente == null){
				nombreCliente = "invitado";
			}

                        //TODO MODIFICACION
                        String opcion_sala="";
                        do{
                             salida.println("server>Desea crear una sala(1) o ingresar a una(2)");
                             opcion_sala = entrada.readLine().trim();
                        }while(opcion_sala.compareToIgnoreCase("1")!=0 && opcion_sala.compareToIgnoreCase("2")!=0);
                       
                        if(opcion_sala.equalsIgnoreCase("1")){
                            int op=0;
                            do{
                                salida.println("server>Ingrese nombre de sala a crear:");
                                nombreSala = entrada.readLine().trim();
                                for (Object obj : salas) {
                                    String sala = (String)obj;
                                    System.out.println(">"+sala);
                                    if(sala.compareToIgnoreCase(nombreSala)==0){
                                        salida.println("server>Nombre de sala no disponible");
                                        op=1;
                                        break;
                                    }
                                }
                            }while(op==1);
                            salas.add(nombreSala);
                        }
                        else {
                            int op=0;
                            do{
                                salida.println("server>Ingrese nombre de sala a entrar:");
                                nombreSala = entrada.readLine().trim();
                                for (Object obj : salas) {
                                    String sala = (String)obj;
                                    System.out.println(">"+sala);
                                    if(sala.compareToIgnoreCase(nombreSala)==0){
                                       // salida.println("server>Conectado correctamente a la sala :"+nombreSala);
                                        op=1;
                                        break;
                                    }
                                }
                                if(op==0)
                                     salida.println("server>Nombre de sala no disponible");
                            }while(op==0);

                        }
                        //
			Iterator it = clientesActivos.iterator();
			while(it.hasNext()){
				if(nombreCliente.equals(((ThreadServidor)it.next()).nombreCliente)){
					nombreCliente = nombreCliente + socket.getPort();
					break;
				}
			}
			
			añadirConexion(this);
			//escribirATodos("server>Se agrego a la sala :  " + nombreCliente);
                        escribirATodosSala("server>Se agrego a la sala :  " + nombreCliente,nombreSala);
			salida.println("server>Se le asigno el alias de " + nombreCliente);
			
			socket.setSoTimeout(ServidorChat.TIEMPO_DESCONEXION_AUTOMATICA);
			
			while((textoUsuario = entrada.readLine()) != null && ServidorChat.estado){ //o while(true)
				if(textoUsuario.compareToIgnoreCase("!salir") == 0){
					escribirATodos("server>Se desconecto de la sala :  " + nombreCliente);
					salida.println("server>*******Hasta la vista baby*******");
					escribirHistorial("Desconexion voluntaria desde la direccion :");
					break;
				}else if(textoUsuario.compareToIgnoreCase("!listar") == 0){
					escribirCliente(this,"server>" + listarClientesActivosSala(nombreSala));
				}else if(textoUsuario.compareToIgnoreCase("!ayuda") == 0){
					escribirCliente(this,"server>" +"!listar,!salir,!priv:<nombre_usuario>:<mensaje>");
				}else if(textoUsuario.indexOf("!priv:") == 0){
                                        String[] cad = textoUsuario.split(":");
					escribirAUnoSala(cad[1],nombreSala,nombreCliente + "(privado)" +">" + cad[2]);
				}
                                else{
					//escribirATodos(nombreCliente + ">" + textoUsuario);
                                        escribirATodosSala(nombreCliente + ">" + textoUsuario,nombreSala);
				}
				
			}
                        if(!ServidorChat.estado)
                            salida.println("server>*******El Servidor ha sido parado!!..disculpe!!*******");

		}catch(InterruptedIOException e1){
			escribirCliente(this,">" +"*******************");
			escribirCliente(this,">" +"Se le paso el tiempo : Conexion cerrada");
			escribirCliente(this,">" +"Si desea continuar..abra otra sesion");
			escribirCliente(this,">" +"*********BYTE**********");
			
			escribirHistorial("Desconexion por fin de tiempo desde la direccion");
			
		}catch(IOException e2){
			escribirHistorial("Desconexion involuntaria desde la direccion");
		}
		finally{
			eliminarConexion(this);
			limpiar();
		}
	}
	
	public void limpiar(){
		if(entrada != null){
			try{
				entrada.close();
			}catch(IOException e1){
				entrada = null;
			}
		}
		if(salida != null){
			salida.close();
			salida = null;	
		}
		if(socket != null){
			try{
				socket.close();
			}catch(IOException e2){
				socket = null;
			}
		}
	}
	
	private static synchronized void eliminarConexion(ThreadServidor thread_servidor){
		clientesActivos.remove(thread_servidor);
	}	
		
	private static synchronized void añadirConexion(ThreadServidor thread_servidor){
		clientesActivos.add(thread_servidor);
	}
	
	private synchronized void escribirATodos(String texto_usuario){
		Iterator it = clientesActivos.iterator();
		
		//Se envia el texto a todos los usuarios, excepto al q loha escrito.
		while(it.hasNext()){
			ThreadServidor temp = (ThreadServidor)it.next();
			if(!(temp.equals(this))){
				escribirCliente(temp,texto_usuario);
			}
		}
	}

        private synchronized void escribirATodosSala(String texto_usuario, String sala){
		Iterator it = clientesActivos.iterator();
		//Se envia el texto a todos los usuarios, excepto al q loha escrito.
		while(it.hasNext()){
			ThreadServidor temp = (ThreadServidor)it.next();
			if(!(temp.equals(this))){
                                if(temp.nombreSala.compareToIgnoreCase(sala)==0)
                                    escribirCliente(temp,texto_usuario);
			}
		}
	}

        private synchronized void escribirAUnoSala(String cliente, String sala, String texto_usuario){
		Iterator it = clientesActivos.iterator();
		//Se envia el texto a todos los usuarios, excepto al q loha escrito.
		while(it.hasNext()){
			ThreadServidor temp = (ThreadServidor)it.next();
			if(!(temp.equals(this))){
                                if(temp.nombreSala.compareToIgnoreCase(sala)==0 && temp.nombreCliente.compareToIgnoreCase(cliente)==0)
                                    escribirCliente(temp,texto_usuario);
			}
		}
	}
	
	private synchronized void escribirCliente(ThreadServidor thread_servidor, String texto_usuario){
		thread_servidor.salida.println(texto_usuario);
	}	
		
	private synchronized StringBuffer listarClientesActivos(){
		//Se usa StringBuffer por eficacia
		StringBuffer cadena = new StringBuffer();
		for (int i = 0 ; i < clientesActivos.size() ; i++){
			ThreadServidor tmp = (ThreadServidor) clientesActivos.get(i);
			cadena.append(tmp.nombreCliente).append("||");
		} 
		return cadena;	
	}

        private synchronized StringBuffer listarClientesActivosSala(String sala){
		//Se usa StringBuffer por eficacia
		StringBuffer cadena = new StringBuffer();
		for (int i = 0 ; i < clientesActivos.size() ; i++){
			ThreadServidor tmp = (ThreadServidor) clientesActivos.get(i);
                        if(tmp.nombreSala.compareToIgnoreCase(sala)==0){
                            if(i!=0)
                                cadena.append(",").append(tmp.nombreCliente);
                            else
                                cadena.append(tmp.nombreCliente);
                        }
                            
		}
		return cadena;
	}
	
	private synchronized void escribirHistorial(String mensaje){
		PrintWriter salidaArchivo = null;
		try{
			salidaArchivo = new PrintWriter(new BufferedWriter(new FileWriter(historial,true))); //true = autoflush
			salidaArchivo.println(mensaje + " " + socket.getInetAddress().getHostName() + " por el puerto " + socket.getPort() + " en la fecha " + new Date());
			
		}catch(IOException e1){
			System.out.println("Fallo en el archivo de historial");
		}
		finally{
			//limpieza de salida de archivo
			if(salida != null)
				salidaArchivo.close();
				salidaArchivo = null;
		}
	} 		
}
